package db

import "fmt"

type User struct {
	Id   int
	Age  int
	Name string
}

func QueryRowDemo(id int) {
	sqlStr := "select id, name, age from db_user where id=?"
	var u User
	// 非常重要:确保QueryRow之后调用Scan方法,否则持有数据的连接不会被释放
	err := Db.QueryRow(sqlStr, id).Scan(&u.Id, &u.Name, &u.Age)
	if err != nil {
		fmt.Printf("scan failed, err: %v\n", err)
		return
	}
	fmt.Printf("id:%d, name:%s, age:%d\n", u.Id, u.Name, u.Age)
}

func QueryMultiRowDemo(id int) {
	sqlStr := "select id, name, age from db_user where id > ?"
	userList := make([]User, 0, 120)
	//userList := []User{1, "s", 3}

	rows, err := Db.Query(sqlStr, id)
	if err != nil {
		fmt.Printf("query failed, err: %v\n", err)
		return
	}
	// 非常重要,关闭rows释放持有的数据库连接
	defer rows.Close()
	// 循环读取结果集中的数据
	for rows.Next() {
		var u User
		err := rows.Scan(&u.Id, &u.Name, &u.Age)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		userList = append(userList, u)
		fmt.Printf("id: %d, name: %s, age: %d\n", u.Id, u.Name, u.Age)
	}
	fmt.Printf("%#v", userList)
}

// PrepareQueryDemo 预处理查询：优化MySQL服务器重复执行SQL的方法，可以提升服务器性能，提前让服务器编译，一次编译多次执行，节省后续编译的成本。
// 避免SQL注入问题
// 插入、更新和删除操作的预处理十分类似。
func PrepareQueryDemo(id int) {
	sqlStr := "select id, name, age from db_user where id > ?"
	stmt, err := Db.Prepare(sqlStr)
	if err != nil {
		fmt.Printf("preare failed, err: %v\n", err)
		return
	}
	defer stmt.Close()
	rows, err := stmt.Query(id)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	defer rows.Close()

	// 循环读取结果集中的数据
	for rows.Next() {
		var u User
		err := rows.Scan(&u.Id, &u.Name, &u.Age)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id:%d, name: %s, age:%d", u.Id, u.Name, u.Age)
	}
}

// SqlInjectDemo 自行拼接SQL语句的示例, 任何时候都不应该自己拼接 SQL语句
func SqlInjectDemo(name string) {
	sqlStr := fmt.Sprintf("select id, name, age from db_user where name=%s", name)
	fmt.Println("拼接的SQL:", sqlStr)
	var u User
	err := Db.QueryRow(sqlStr).Scan(&u.Id, &u.Name, &u.Age)
	if err != nil {
		fmt.Println("exec failed, err:", err)
		return
	}
	fmt.Printf("user: %#v", u)
}
